package com.github.grpc.client.service.impl;

import com.github.grpc.client.property.GrpcChannelProperties;
import com.github.grpc.client.property.GrpcChannelsProperties;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.github.grpc.client.service.AddressChannelResolverFactory;
import com.github.grpc.client.service.GlobalClientInterceptorRegistry;
import com.github.grpc.client.service.GrpcChannelFactory;
import com.github.grpc.client.utils.CertFileUtil;
import io.grpc.*;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NegotiationType;
import io.grpc.netty.NettyChannelBuilder;
import io.netty.handler.ssl.SslContext;

import javax.net.ssl.SSLException;
import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Grpc服务直连工厂类
 */
public class AddressChannelFactory implements GrpcChannelFactory {
    private final GrpcChannelsProperties properties;
    private final LoadBalancer.Factory loadBalancerFactory;
    private final NameResolver.Factory nameResolverFactory;
    private final GlobalClientInterceptorRegistry globalClientInterceptorRegistry;

    public AddressChannelFactory(GrpcChannelsProperties properties, LoadBalancer.Factory loadBalancerFactory, GlobalClientInterceptorRegistry globalClientInterceptorRegistry) {
        this.properties = properties;
        this.loadBalancerFactory = loadBalancerFactory;
        this.nameResolverFactory = new AddressChannelResolverFactory(properties);
        this.globalClientInterceptorRegistry = globalClientInterceptorRegistry;
    }

    @Override
    public Channel createChannel(List<ClientInterceptor> interceptors) {
        NettyChannelBuilder builder = NettyChannelBuilder.forTarget(properties.getDomain())
                .loadBalancerFactory(loadBalancerFactory)
                .nameResolverFactory(nameResolverFactory)
                .usePlaintext(properties.isPlaintext());

        if (properties.isEnableKeepAlive()) {
            builder.keepAliveWithoutCalls(properties.isKeepAliveWithoutCalls())
                    .keepAliveTime(properties.getKeepAliveTime(), TimeUnit.SECONDS)
                    .keepAliveTimeout(properties.getKeepAliveTimeout(), TimeUnit.SECONDS);
        }

        if(properties.isTls()){

            SslContext sslContext = null;
            try {

                File cert = CertFileUtil.getFile(properties.getCertificate());
                sslContext = GrpcSslContexts.forClient().trustManager(cert).build();
            } catch (SSLException e) {
                e.printStackTrace();
            }

           builder.sslContext(sslContext).negotiationType(NegotiationType.TLS);
        }

        if (properties.getMaxInboundMessageSize() > 0) {
            builder.maxInboundMessageSize(properties.getMaxInboundMessageSize());
        }
        Channel channel = builder.build();

        List<ClientInterceptor> globalInterceptorList = globalClientInterceptorRegistry.getClientInterceptors();
        Set<ClientInterceptor> interceptorSet = Sets.newHashSet();
        if (globalInterceptorList != null && !globalInterceptorList.isEmpty()) {
            interceptorSet.addAll(globalInterceptorList);
        }
        if (interceptors != null && !interceptors.isEmpty()) {
            interceptorSet.addAll(interceptors);
        }
        return ClientInterceptors.intercept(channel, Lists.newArrayList(interceptorSet));
    }
}
